package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.TermQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQueryField;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.Suggestion;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.base.BaseEntity;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.suggest.Completion;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Slf4j
@Service
@SuppressWarnings({"all"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private AlbumIndexRepository albumIndexRepository;

    @Autowired
    private SuggestIndexRepository suggestIndexRepository;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 上架专辑
     * 此方法用于将专辑信息保存到Elasticsearch中，以便进行搜索。
     *
     * @param albumId 要上架的专辑的ID
     */
    @Override
    public void upperAlbum(Long albumId) {

        // 创建一个AlbumInfoIndex对象
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();

        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            // 根据专辑id查询专辑信息
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            AlbumInfo albumInfo = albumInfoResult.getData();
            Assert.notNull(albumInfo, "专辑不存在");
            // 属性拷贝
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            return albumInfo;
        }, threadPoolExecutor);

        CompletableFuture<Void> attributeValuecompletableFuture = CompletableFuture.runAsync(() -> {
            // 根据专辑id查询专辑属性值
            Result<List<AlbumAttributeValue>> albumAttributeValueResult = albumInfoFeignClient.findAlbumAttributeValue(albumId);
            Assert.notNull(albumAttributeValueResult, "专辑属性值结果集不存在");
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueResult.getData();
            Assert.notNull(albumAttributeValueList, "专辑属性值不存在");
            // albumAttributeValueList 循环遍历当前集合，获取到  attributeId  valueId 给 albumInfoIndex 中的属性赋值！
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueList.stream().map(albumAttributeValue -> {
                // 创建一个AttributeValueIndex对象
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                // 返回数据
                return attributeValueIndex;
            }).collect(Collectors.toList());
            // 将attributeValueIndexList赋值给albumInfoIndex
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
        }, threadPoolExecutor);

        CompletableFuture<Void> categoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 根据三级分类id查询分类信息
            Result<BaseCategoryView> baseCategoryViewResult = categoryFeignClient.getCategoryView(albumInfo.getCategory3Id());
            Assert.notNull(baseCategoryViewResult, "分类结果集不存在");
            BaseCategoryView baseCategoryView = baseCategoryViewResult.getData();
            Assert.notNull(baseCategoryView, "分类不存在");
            // 赋值分类数据
            albumInfoIndex.setCategory1Id(baseCategoryView.getCategory1Id());
            albumInfoIndex.setCategory2Id(baseCategoryView.getCategory2Id());
        }, threadPoolExecutor);

        CompletableFuture<Void> userCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
            // 根据用户id查询用户信息
            Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(albumInfo.getUserId());
            Assert.notNull(userInfoVoResult, "用户结果集不存在");
            UserInfoVo userInfoVo = userInfoVoResult.getData();
            Assert.notNull(userInfoVo, "用户不存在");
            // 赋值主播名称
            albumInfoIndex.setAnnouncerName(userInfoVo.getNickname());
        }, threadPoolExecutor);

        // 初始化专辑的统计数据
        albumInfoIndex.setBuyStatNum(new Random().nextInt(1000000));
        albumInfoIndex.setPlayStatNum(new Random().nextInt(1000000));
        albumInfoIndex.setCommentStatNum(new Random().nextInt(1000000));
        albumInfoIndex.setSubscribeStatNum(new Random().nextInt(1000000));

        // 进行多任务组合
        CompletableFuture.allOf(
                albumInfoCompletableFuture,
                attributeValuecompletableFuture,
                categoryCompletableFuture,
                userCompletableFuture
        ).join();

        log.info("上架专辑：{}" + albumInfoIndex);
        // 将整个对象保存到es中
        albumIndexRepository.save(albumInfoIndex);

        // 上架添加提词数据
        // 创建对象 专辑标题提词
        SuggestIndex suggestIndex = new SuggestIndex();
        suggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        suggestIndex.setTitle(albumInfoIndex.getAlbumTitle());
        suggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumTitle()}));
        suggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumTitle())}));
        suggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumTitle())}));
        this.suggestIndexRepository.save(suggestIndex);

        // 专辑简介提词
        SuggestIndex albumIntroSuggestIndex = new SuggestIndex();
        albumIntroSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        albumIntroSuggestIndex.setTitle(albumInfoIndex.getAlbumIntro());
        albumIntroSuggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAlbumIntro()}));
        albumIntroSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAlbumIntro())}));
        albumIntroSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAlbumIntro())}));
        this.suggestIndexRepository.save(albumIntroSuggestIndex);

        // 专辑主播提词
        SuggestIndex announcerSuggestIndex = new SuggestIndex();
        announcerSuggestIndex.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        announcerSuggestIndex.setTitle(albumInfoIndex.getAnnouncerName());
        announcerSuggestIndex.setKeyword(new Completion(new String[]{albumInfoIndex.getAnnouncerName()}));
        announcerSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumInfoIndex.getAnnouncerName())}));
        announcerSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumInfoIndex.getAnnouncerName())}));
        suggestIndexRepository.save(announcerSuggestIndex);
    }

    /**
     * 下架专辑
     * 此方法用于从数据库中删除指定ID的专辑索引它通常在用户需要彻底删除一个专辑时被调用
     *
     * @param albumId 要删除的专辑的唯一标识符
     */
    @Override
    public void lowerAlbum(Long albumId) {
        albumIndexRepository.deleteById(albumId);
    }

    /**
     * 根据关键字检索专辑
     * 此方法用于根据关键字检索专辑，并返回搜索结果
     *
     * @param albumIndexQuery
     * @return
     */
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        // 1. 创建查询DSL
        SearchRequest searchRequest = this.queryBuildDsl(albumIndexQuery);
        // 2. 执行search方法
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 3. 创建albumSearchResponseVo对象
        // 3.1 将searchResponse中的数据赋值给albumSearchResponseVo对象
        AlbumSearchResponseVo albumSearchResponseVo = this.parseResultData(searchResponse);
        // 3.2 将albumSearchResponseVo属性赋值
        // 总记录表
        albumSearchResponseVo.setTotal(searchResponse.hits().total().value());
        // 每页显示的条数
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        // 当前页码
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        // 总页数
        albumSearchResponseVo.setTotalPages((albumSearchResponseVo.getTotal() + albumSearchResponseVo.getPageSize() - 1) / albumSearchResponseVo.getPageSize());
        // 4. 返回结果
        return albumSearchResponseVo;
    }

    /**
     * 构建查询DSL
     *
     * @param albumIndexQuery
     * @return
     */
    private SearchRequest queryBuildDsl(AlbumIndexQuery albumIndexQuery) {
        // 创建SearchRequest对象
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        // 设置索引名称
        searchRequestBuilder.index("albuminfo");
        // 创建Query对象
        Query.Builder queryBuilder = new Query.Builder();
        // 创建Bool对象
        BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();

        // 1. 判断用户是否根据关键词检索
        if (!StringUtils.isEmpty(albumIndexQuery.getKeyword())) {
            boolQueryBuilder.should(s -> s.match(m -> m.field("albumTitle").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("albumIntro").query(albumIndexQuery.getKeyword())))
                    .should(s -> s.match(m -> m.field("announcerName").query(albumIndexQuery.getKeyword())));
            // 关键字高亮
            searchRequestBuilder.highlight(h -> h.fields("albumTitle", hf -> hf.preTags("<span style='color:red'>").postTags("</span>")));
        }

        // 2. 判断用户是否根据分类检索
        if (null != albumIndexQuery.getCategory3Id()) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category3Id").value(albumIndexQuery.getCategory3Id())));
        }
        if (null != albumIndexQuery.getCategory2Id()) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category2Id").value(albumIndexQuery.getCategory2Id())));
        }
        if (null != albumIndexQuery.getCategory1Id()) {
            boolQueryBuilder.filter(f -> f.term(t -> t.field("category1Id").value(albumIndexQuery.getCategory1Id())));
        }

        // 3. 根据属性进行过滤 属性id:属性值id
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)) {
            for (String attribute : attributeList) {
                String[] split = attribute.split(":");
                if (null != split && split.length == 2) {
                    boolQueryBuilder.filter(f -> f.nested(n -> n.path("attributeValueIndexList")
                            .query(q -> q.bool(b -> b.filter(bf -> bf.term(t -> t.field("attributeValueIndexList.attributeId").value(split[0])))
                                    .filter(bf -> bf.term(t -> t.field("attributeValueIndexList.valueId").value(split[1])))
                            ))));
                }
            }
        }

        // 4. 分页，排序
        int from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        searchRequestBuilder.from(from);
        searchRequestBuilder.size(albumIndexQuery.getPageSize());

        // 5. 获取排序规则 综合排序[1:desc] 播放量[2:desc] 发布时间[3:desc]；asc:升序 desc:降序
        String order = albumIndexQuery.getOrder();
        if (!StringUtils.isEmpty(order)) {
            String[] split = order.split(":");
            if (null != split && split.length == 2) {
                // 声明一个排序字段
                String field = "";
                // 判断根据哪个字段排序
                switch (split[0]) {
                    case "1":
                        field = "hotScore";
                        break;
                    case "2":
                        field = "playStatNum";
                        break;
                    case "3":
                        field = "createTime";
                        break;
                }
                // 设置排序规则
                String finalField = field;
                searchRequestBuilder.sort(s -> s.field(f -> f.field(finalField).order("asc".equals(split[1]) ? SortOrder.Asc : SortOrder.Desc)));
            }
        }

        // 调用boolQueryBuilder.build()方法生成BoolQuery对象
        BoolQuery boolQuery = boolQueryBuilder.build();
        // 调用queryBuilder.bool()方法将BoolQuery对象添加到Query对象中
        queryBuilder.bool(boolQuery);
        // 调用queryBuilder.bool()方法生成Query对象
        Query query = queryBuilder.build();
        // 调用searchRequestBuilder.query()方法将Query对象添加到SearchRequest对象中
        searchRequestBuilder.query(query);
        // 调用SearchRequestBuilder.build()方法生成SearchRequest对象
        SearchRequest searchRequest = searchRequestBuilder.build();
        // 打印DSL
        System.out.println("dsl:\t" + searchRequest.toString());
        // 返回对象
        return searchRequest;
    }

    /**
     * 解析搜索响应数据
     * 此方法将从Elasticsearch搜索响应中提取的专辑信息转换为专辑搜索响应对象
     * 它处理搜索结果的解析，将每个命中的文档映射到一个专辑信息视图对象，并汇总到搜索响应对象中
     *
     * @param searchResponse 搜索响应对象，包含命中的专辑信息文档
     * @return AlbumSearchResponseVo 包含解析后的专辑信息的搜索响应视图对象
     */
    private AlbumSearchResponseVo parseResultData(SearchResponse<AlbumInfoIndex> searchResponse) {
        // 创建专辑搜索响应视图对象实例
        // 主要给 private List<AlbumInfoIndexVo> list = new ArrayList<>(); 属性赋值;
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        // 提取搜索响应中的命中文档
        List<Hit<AlbumInfoIndex>> hits = searchResponse.hits().hits();
        // 将命中的文档流映射为专辑信息视图对象流，并收集到列表中
        List<AlbumInfoIndexVo> list = hits.stream().map(hit -> {
            // 创建专辑信息视图对象实例
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            // 获取命中文档的源数据
            AlbumInfoIndex albumInfoIndex = hit.source();
            // 将源数据的属性复制到视图对象中
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            // 如果文档的专辑标题被高亮显示，则更新视图对象的专辑标题为高亮显示的值
            if (null != hit.highlight().get("albumTitle")) {
                String albumTitle = hit.highlight().get("albumTitle").get(0);
                albumInfoIndexVo.setAlbumTitle(albumTitle);
            }
            // 返回映射后的视图对象
            return albumInfoIndexVo;
        }).collect(Collectors.toList());
        // 将收集到的专辑信息视图对象列表设置到搜索响应视图对象中
        albumSearchResponseVo.setList(list);
        // 返回填充好的搜索响应视图对象
        return albumSearchResponseVo;
    }

    /**
     * 获取频道页数据
     *
     * @param category1Id
     * @return
     */
    @Override
    public List<Map<String, Object>> channel(Long category1Id) {
        // 先获取分类对象，再获取专辑列表
        Result<List<BaseCategory3>> baseCategory3ListResult = categoryFeignClient.findTopBaseCategory3(category1Id);
        Assert.notNull(baseCategory3ListResult, "分类结果集为空");
        List<BaseCategory3> baseCategory3List = baseCategory3ListResult.getData();
        Assert.notNull(baseCategory3List, "分类列表为空");
        // 将baseCategory3List转换为Map 键：category3Id 值：category3;
        Map<Long, BaseCategory3> baseCategory3Map = baseCategory3List.stream().collect(Collectors.toMap(BaseCategory3::getId, baseCategory3 -> baseCategory3));
        List<Long> category3IdList = baseCategory3List.stream().map(BaseCategory3::getId).collect(Collectors.toList());
        List<FieldValue> valueList = category3IdList.stream().map(category3Id -> FieldValue.of(category3Id)).collect(Collectors.toList());
        // 创建查询对象
        SearchResponse<AlbumInfoIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                            .query(q -> q.terms(t -> t.field("category3Id")
                                    .terms(tm -> tm.value(valueList))))
                            .aggregations("aggCategory3Id", a -> a.terms(t -> t.field("category3Id"))
                                    .aggregations("aggTopSix", a2 -> a2.topHits(th -> th.size(6)
                                            .sort(st -> st.field(f -> f.field("buyStatNum").order(SortOrder.Desc))))))
                    , AlbumInfoIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 获取搜索响应中名为"aggCategory3Id"的聚合结果
        Aggregate aggCategory3Id = searchResponse.aggregations().get("aggCategory3Id");
        // 将聚合结果转换为列表，每个元素包含分类ID和对应的专辑信息列表
        List<Map<String, Object>> list = aggCategory3Id.lterms().buckets().array().stream().map(bucket -> {
            // 创建一个哈希表来存储分类信息和对应的专辑信息列表
            Map<String, Object> hashMap = new HashMap<>();
            // 从桶中获取分类ID
            long category3Id = bucket.key();
            // 获取当前分类下名为"aggTopSix"的聚合结果，用于获取前六个热门专辑
            Aggregate aggTopSix = bucket.aggregations().get("aggTopSix");
            // 将聚合结果中的热门专辑转换为AlbumInfoIndex对象列表
            List<AlbumInfoIndex> albumInfoIndexList = aggTopSix.topHits().hits().hits().stream().map(hit -> {
                // 将搜索结果的源数据转换为AlbumInfoIndex对象
                AlbumInfoIndex albumInfoIndex = JSON.parseObject(hit.source().toString(), AlbumInfoIndex.class);
                return albumInfoIndex;
            }).collect(Collectors.toList());
            // 将分类信息和专辑信息列表添加到哈希表中
            hashMap.put("baseCategory3", baseCategory3Map.get(category3Id));
            hashMap.put("list", albumInfoIndexList);
            // 返回包含分类信息和专辑信息列表的哈希表
            return hashMap;
        }).collect(Collectors.toList());
        // 返回转换后的列表
        return list;
    }

    /**
     * 关键字自动补全
     *
     * @param keyword
     * @return
     */
    @Override
    public List<String> completeSuggest(String keyword) {
        SearchResponse<SuggestIndex> searchResponse = null;
        try {
            searchResponse = elasticsearchClient.search(i -> i.index("suggestinfo")
                            .suggest(s -> s.suggesters("ts-suggest-keyword",
                                            s1 -> s1.prefix(keyword).completion(c -> c.field("keyword")
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .skipDuplicates(true)))
                                    .suggesters("ts-suggest-keywordPinyin",
                                            s1 -> s1.prefix(keyword).completion(c -> c.field("keywordPinyin")
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .skipDuplicates(true)))
                                    .suggesters("ts-suggest-keywordSequence",
                                            s1 -> s1.prefix(keyword).completion(c -> c.field("keywordSequence")
                                                    .fuzzy(f -> f.fuzziness("auto"))
                                                    .skipDuplicates(true)))
                            )
                    , SuggestIndex.class);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 获取数据
        List<String> list = new ArrayList<>();
        list.addAll(this.getSuggestTitle(searchResponse, "ts-suggest-keyword"));
        list.addAll(this.getSuggestTitle(searchResponse, "ts-suggest-keywordPinyin"));
        list.addAll(this.getSuggestTitle(searchResponse, "ts-suggest-keywordSequence"));
        // 返回集合
        return list;
    }

    private Collection<String> getSuggestTitle(SearchResponse<SuggestIndex> searchResponse, String keyword) {
        List<Suggestion<SuggestIndex>> suggestionList = searchResponse.suggest().get(keyword);
        for (Suggestion<SuggestIndex> suggestIndexSuggestion : suggestionList) {
            // 获取数据
            List<String> list = suggestIndexSuggestion.completion().options().stream().map(suggestIndexCompletionSuggestOption -> {
                return suggestIndexCompletionSuggestOption.source().getTitle();
            }).collect(Collectors.toList());
            // 返回数据
            return list;
        }
        return null;
    }

    /**
     * 更新排行榜
     */
    @Override
    public void updateLatelyAlbumRanking() {
        // 获取所有一级分类Id列表
        Result<List<BaseCategory1>> baseCategory1Result = categoryFeignClient.findAllCategory1();
        Assert.notNull(baseCategory1Result, "一级分类结果集为空");
        List<BaseCategory1> baseCategory1List = baseCategory1Result.getData();
        // 循环遍历
        for (BaseCategory1 baseCategory1 : baseCategory1List) {
            // 五个维度
            String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
            for (String ranking : rankingDimensionArray) {
                // 执行dsl语句
                SearchResponse<AlbumInfoIndex> searchResponse = null;
                try {
                    searchResponse = elasticsearchClient.search(s -> s.index("albuminfo")
                                    .query(q -> q.term(t -> t.field("category1Id").value(baseCategory1.getId())))
                                    .sort(st -> st.field(f -> f.field(ranking).order(SortOrder.Desc)))
                            , AlbumInfoIndex.class);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                // 获取数据 Hash: hset key field value;
                List<AlbumInfoIndex> albumInfoIndexList = searchResponse.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
                // 并放入缓存;
                this.redisTemplate.opsForHash().put(RedisConstant.RANKING_KEY_PREFIX + baseCategory1.getId(), ranking, albumInfoIndexList);
            }
        }
    }

    /**
     * 获取排行榜
     *
     * @param baseCategory1Id
     * @param ranking
     * @return
     */
    @Override
    public List<AlbumInfoIndex> findRankingList(Long baseCategory1Id, String ranking) {
        return (List<AlbumInfoIndex>) this.redisTemplate.opsForHash().get(RedisConstant.RANKING_KEY_PREFIX + baseCategory1Id, ranking);
    }

}





















